#include "View.h"
#include "../Gui/ViewsContainer.h"

using namespace std;
using namespace CICore;
using namespace CIGeom;
using namespace CIOps;

///<************************************************************************************************************>
///<************************************* region CONSTANTS DEFINITION ******************************************>
///<************************************************************************************************************>

const Color CIView::View::DEFAULT_BACKGROUND_COLOR (0.05f, 0.05f, 0.05f);
const Color CIView::View::ON_FOCUS_BACKGROUND_COLOR (0.0f, 0.0f, 0.0f);

CIView::GridGround CIView::View::gridGround = GridGround::GridGround();
/***************************************************************************************************************
**************************************** endregion CONSTANTS DEFINITION ****************************************
****************************************************************************************************************/



//Static public variables
CIView::FeedbackTranslation CIView::View::Feedback_Translation;    //The translation feedback
CIView::FeedbackScaling CIView::View::Feedback_Scaling;            //The scaling feedback
CIView::FeedbackRotation CIView::View::Feedback_Rotation;          //The rotation feedback



/// <summary>
/// Constructor
/// </summary>
/// <param name="type"> The current camera's type </param>
/// <param name="s"> A reference to the 3D scene to show </param>
/// <param name="om"> A reference to the application operations manager </param>
/// <param name="parent"> The parent widget </param>
CIView::View::View (Camera::CameraType type, Scene& s, OperationManager& om, QWidget* parent)
: QGLWidget(parent), scene (s), polygonMode (GL_LINE),
  operationManager (om), feedbackMode (FEEDBACK_NONE), incrZ (0) {

    //Creating the 4 basic cameras
    cameras.push_back (new Camera (Camera::TOP));       //Camera TOP
    cameras.push_back (new Camera (Camera::FRONT));     //Camera FRONT
    cameras.push_back (new Camera (Camera::RIGHT));     //Camera RIGHT
    cameras.push_back (new Camera (Camera::USER));      //Camera USER (3D view)

    camera = cameras[type];                             //Sets the current camera

    CurrentInteractiveAction = NONE;                    //Sets the current interactive action as NONE
}

/// <summary>
/// Destructor
/// </summary>
CIView::View::~View() {
    //Deleting all cameras
    vector<Camera*>::iterator it = cameras.begin();

    while (it != cameras.end())
        delete (*it++);
}









///<************************************************************************************************************>
///<****************************************** region Public SLOTS *********************************************>
///<************************************************************************************************************>

/// <summary>
/// Slot method called to select the camera
/// </summary>
/// <param name="index"> The camera required </param>
void CIView::View::SelectCamera (int index) {
    if (index < 0 || index >= cameras.size())       //Checking out of range errors
        return;

    camera = cameras[index];                        //Sets the current camera

    if (camera->type == Camera::USER)               //If the camera selected is of type Camera::USER
        CurrentInteractiveAction = NONE;            //sets the current interactive action as NONE
    else {} //TODO -> if there is a view with interactive action different of NONE, has to set that action for this view too

    SetProjection();                                //Updates the projection matrix

    emit CurrentCameraChanged (index);              //Singals that the current camera has changed

    updateGL();                                     //Updates the view
}

/// <summary>
/// Slot method called to set camera's orientation
/// </summary>
/// <param name="x"> The x-axis orientation angle value </param>
/// <param name="y"> The y-axis orientation angle value </param>
/// <param name="z"> The z-axis orientation angle value </param>
void CIView::View::SetCameraOrientation (int x, int y, int z) {
    bool changed = camera->orientation.x != x
                   || camera->orientation.y != y
                   || camera->orientation.z != z;   //Checks if camera's orientation has changed

    if (changed) {                                  //If camera's orientation has changed
        camera->orientation.x = x;                  //updates orientation values
        camera->orientation.y = y;
        camera->orientation.z = z;

        emit CameraOrientationChanged (x, y, z);    //signals that camera's orientation has changed

        if (CurrentInteractiveAction == NONE)       //If the current interactive action is none
            updateGL();                             //updates the view
    }
}

/// <summary>
/// Slot method called to set the View Reference Point (VRP) value
/// </summary>
/// <param name="x"> The new View Reference Point x-axis value </param>
/// <param name="y"> The new View Reference Point y-axis value </param>
/// <param name="z"> The new View Reference Point z-axis value </param>
void CIView::View::SetVRP (float x, float y, float z) {
    //Updating the VRP value
    camera->vrp.x = x;
    camera->vrp.y = y;
    camera->vrp.z = z;

    emit VrpChanged (x, y, z);      //Signals that the VRP value has changed

    updateGL();                     //Updates the view
}

/// <summary>
/// Slot method called to modify the zoom value
/// </summary>
/// <param name="z"> The value to be added to the zoom </param>
void CIView::View::SetZoomFactor (float f) {
    if (f == camera->zoom ||            //If the zoom has not changed
        f < 0.2f || f > 200.0f)         //or the new value is out of range
            return;                     //must return

    camera->zoom = f;                   //Sets the new zoom value

    SetProjection();                    //Updates the projection matrix

    emit ZoomFactorChanged (f);         //Signals that the zoom value has changed

    updateGL();                         //Updates the view
}

/// <summary>
/// Slot method called to set the selection status
/// (No primitive selected or Some primitive selected)
/// </summary>
/// <param name="b"> A boolean to indicate if some primitive has been selected or not </param>
void CIView::View::SetPrimitivesSelected (bool b) {
    emit PrimitivesSelected (b);
}

/// <summary>
/// Slot method called to reset the current camera parameters
/// </summary>
void CIView::View::ResetCurrentCamera() {
    makeCurrent();

    camera->Reset();

    emit CurrentCameraReset (true);

    int vp[4];
    glGetIntegerv (GL_VIEWPORT, vp);

    resizeGL (vp[2], vp[3]);

    updateGL();
}

/// <summary>
/// Slot method called to enable/disable lighting
/// </summary>
void CIView::View::ToggleLighting() {
    makeCurrent();

    if (glIsEnabled (GL_LIGHTING)) {
        glDisable (GL_LIGHTING);
        emit LightingEnabled (false);
    }
    else {
        glEnable (GL_LIGHTING);
        emit LightingEnabled (true);
    }

    updateGL();
}

/// <summary>
/// Slot method called to select the current shade model
/// </summary>
/// <param name="model"> The id of the mode required </param>
void CIView::View::SelectShadeModel (int model) {
    makeCurrent();

    switch (model) {
        case WIREFRAME:
            polygonMode = GL_LINE;
            break;

        case FLAT:
            polygonMode = GL_FILL;
            glShadeModel (GL_FLAT);
            break;

        case SMOOTH:
            polygonMode = GL_FILL;
            glShadeModel (GL_SMOOTH);
            break;
    }

    glPolygonMode (GL_FRONT_AND_BACK, polygonMode);

    emit ShadeModelChanged();

    updateGL();
}
/***************************************************************************************************************
******************************************* endregion Public SLOTS *********************************************
****************************************************************************************************************/





///<************************************************************************************************************>
///<*********************************** region Protected Utility Methods ***************************************>
///<************************************************************************************************************>

/// <summary>
/// Virtual function called once before the first call to paintGL() or resizeGL()
/// to initialize the openGL environment and all needed variables
/// </summary>
void CIView::View::initializeGL() {
    setFocusPolicy (Qt::StrongFocus);                   //Enables keyboard events

    glClearColor (DEFAULT_BACKGROUND_COLOR.r,
                  DEFAULT_BACKGROUND_COLOR.g,
                  DEFAULT_BACKGROUND_COLOR.b,
                  DEFAULT_BACKGROUND_COLOR.a);          //Sets the clear values for the color buffer

    glPolygonMode (GL_FRONT_AND_BACK, polygonMode);     //Sets the polygon mode for this 3D view

    //glAlphaFunc (GL_GREATER, 0.1f);
    //glEnable (GL_ALPHA_TEST);                           //Enables alpha buffering

    //glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    //glEnable (GL_BLEND);                                //Enables blending

    //glCullFace (GL_BACK);
    //glEnable (GL_CULL_FACE);                            //Enables culling

    //Enabling lighting
    glEnable (GL_LIGHTING);

    //Enabling light 0
    glEnable (GL_LIGHT0);

    //Creating light components
    GLfloat ambientLight[] = { 0.2f, 0.2f, 0.2f, 1.0f };
    GLfloat diffuseLight[] = { 0.8f, 0.8f, 0.8, 1.0f };
    GLfloat specularLight[] = { 0.5f, 0.5f, 0.5f, 1.0f };

    //Assigning created components to GL_LIGHT0
    glLightfv (GL_LIGHT0, GL_AMBIENT, ambientLight);
    glLightfv (GL_LIGHT0, GL_DIFFUSE, diffuseLight);
    glLightfv (GL_LIGHT0, GL_SPECULAR, specularLight);

    //Defining the global ambient
    GLfloat global_ambient[] = { 0.2f, 0.2f, 0.2f, 1.0f };
    glLightModelfv(GL_LIGHT_MODEL_AMBIENT, global_ambient);
    //glLightModelf (GL_LIGHT_MODEL_LOCAL_VIEWER, GL_TRUE);

    //Defining the global shininess
    glMateriali (GL_FRONT, GL_SHININESS, 96);

    //Enabling color tracking and setting material properties which will be assigned by glColor
    glEnable (GL_COLOR_MATERIAL);
    glColorMaterial (GL_FRONT, GL_AMBIENT_AND_DIFFUSE);

    //glFrontFace (GL_CCW);
}

/// <summary>
/// Virtual function called whenever the widget needs to be painted
/// </summary>
void CIView::View::paintGL() {
    glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);    //Clears the color an depth buffers

    //Setting up the model view matrix
    SetModelView();

    //Defining light position
    GLfloat position[] = { 1, 1, 1, 0 };
    glLightfv (GL_LIGHT0, GL_POSITION, position);

    //Drawing
    DrawGridGround();               //Draws the grid ground

    DrawAxes();                     //Draws the axes

    glEnable (GL_DEPTH_TEST);       //Enables z-buffering
    DrawScene();                    //Draws the scene
    glDisable (GL_DEPTH_TEST);      //Disables z-buffering

    DrawFeedback();                 //Draws the feedback (if needed)
}

/// <summary>
/// Virtual method called to set the model view matrix
/// </summary>
void CIView::View::SetModelView() {
    glLoadIdentity();                                           //Loads the identity matrix on the current-matrix-stack top

    //Setting the scene position and orientation
    glTranslatef (0.0f, 0.0f, -camera->vrpDistance);                //Translates the scene in comparison of the camara distance
    glRotatef (camera->orientation.z + incrZ, 0.0f, 0.0f, 1.0f);    //Rotates the scene on z-axis according to the camara orientation
    glRotatef (camera->orientation.x + drag.y, 1.0f, 0.0f, 0.0f);   //Rotates the scene on x-axis according to the camara orientation
    glRotatef (camera->orientation.y + drag.x, 0.0f, 1.0f, 0.0f);   //Rotates the scene on y-axis according to the camara orientation
    glTranslatef (-camera->vrp.x, -camera->vrp.y, -camera->vrp.z);  //Translates the scene in comparison of the view reference point
}

/// <summary>
/// Virtual method called whenever the widget has been resized
/// </summary>
/// <param name="width"> The new widget width </param>
/// <param name="height"> The new widget height </param>
void CIView::View::resizeGL (int width, int height) {
    glViewport (0, 0, width, height);           //Updates the viewport sizes

    float aspectRatio = (float)width/height;

    if (aspectRatio != 1.0f){
     float newWidth = aspectRatio * Camera::WIDTH;
     float incr = newWidth - Camera::WIDTH;

     camera->left = -(Camera::WIDTH  + incr) / 2.0f;
     camera->right = (Camera::WIDTH + incr) / 2.0f;
    }

    //camera->aspectRatio = (float)width/height;  //Sets the aspect ratio value to avoid scene deformation

    SetProjection();                            //Sets the projection matrix
}

/// <summary>
/// Virtual method called to set the projection matrix
/// </summary>
void CIView::View::SetProjection() {
    glMatrixMode (GL_PROJECTION);       //Changes matrix mode to PROJECTION

    glLoadIdentity();                   //Loads the identity matrix on the current-matrix-stack top

    SetViewFrustum();                   //Sets the view frustum

    glMatrixMode (GL_MODELVIEW);        //Changes matrix mode to MODELVIEW
}

/// <summary>
/// Virtual method called to set the view frustum
/// </summary>
void CIView::View::SetViewFrustum() {
    glOrtho (camera->left / camera->zoom,
             camera->right / camera->zoom,
             camera->bottom / camera->zoom,
             camera->top / camera->zoom,
             camera->zNear, camera->zFar);                  //Sets up a orthographic projection

    //gluPerspective (camera->fov / camera->zoom,
    //                camera->aspectRatio,
    //                camera->zNear, camera->zFar);           //Sets up a perspective projection
}

/// <summary>
/// Method called whenever the application needs to paint the grid ground
/// </summary>
void CIView::View::DrawGridGround() {
    glPushMatrix();
        switch (camera->type) {
            //case Camera::TOP:       /* Ground orientation si already ok */
            //    break;

            case Camera::FRONT:
                glRotatef (90.0f, 1.0f, 0, 0);
                break;

            case Camera::RIGHT:
                glRotatef (-90.0f, 0, 0, 1.0f);
                break;

            //case Camera::USER:      /* Ground orientation si already ok */
            //    break;
        }

        gridGround.Render();        //Draws the grid ground
    glPopMatrix();
}

/// <summary>
/// Method called whenever the application needs to paint the axes
/// </summary>
void CIView::View::DrawAxes() {
    glLineWidth (1.0f);                             //Sets the line width

    glBegin( GL_LINES );
        glColor4f (1.0f, 0.0f, 0.0f, 1.0f);        //The x-axis
        glVertex3f (0.0f, 0.0f, 0.0f);
        glVertex3f (4.0f, 0.0f, 0.0f);

        glColor4f (0.0f, 1.0f, 0.0f, 1.0f);        //The y-axis
        glVertex3f (0.0f, 0.0f, 0.0f);
        glVertex3f (0.0f, 4.0f, 0.0f);

        glColor4f (0.0f, 0.0f, 1.0f, 1.0f);        //The z-axis
        glVertex3f (0.0f, 0.0f, 0.0f);
        glVertex3f (0.0f, 0.0f, 4.0f);
    glEnd();
}

/// <summary>
/// Method called whenever the application needs to paint the scene
/// </summary>
void CIView::View::DrawScene() {
    scene.Render();
}

/// <summary>
/// Method called whenever the application needs to paint the feedback
/// </summary>
void CIView::View::DrawFeedback() {
    bool lightingActivated = glIsEnabled (GL_LIGHTING);

    //According to the current feedback mode
    switch (feedbackMode) {
        case FEEDBACK_SELECTION:          //SELECTION
            glPushMatrix();

                if (lightingActivated)
                    glDisable (GL_LIGHTING);

                glColor3f (1.0f, 1.0f, 1.0f);
                glLoadIdentity();
                feedbackSelection.Render (camera->zNear);       //Draws the selection feedback

                if (lightingActivated)
                    glEnable (GL_LIGHTING);
            glPopMatrix();
            break;

        case FEEDBACK_TRANSLATION:        //TRANSLATION
            glPushMatrix();
                glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
                Feedback_Translation.Render (*camera);
                glPolygonMode (GL_FRONT_AND_BACK, polygonMode);
            glPopMatrix();
            break;

        case FEEDBACK_ROTATION:           //ROTATION
            glPushMatrix();
                glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
                Feedback_Rotation.Render (*camera);
                glPolygonMode (GL_FRONT_AND_BACK, polygonMode);
            glPopMatrix();
            break;

        case FEEDBACK_SCALING:            //SCALING
            glPushMatrix();
                glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);
                Feedback_Scaling.Render (*camera);
                glPolygonMode (GL_FRONT_AND_BACK, polygonMode);
            glPopMatrix();
            break;
    }
}

/// <summary>
/// Method called to do panning
/// </summary>
/// <param name="x"> The quantity of panning on the x-axis </param>
/// <param name="y"> The quantity of panning on the y-axis </param>
void CIView::View::DoPanning (int x, int y) {
    float factor = 10 * camera->zoom;               //Factor to make pan considering also the current zoom
    float incr_x = x / factor;                      //Determines the incr value on x-axis for scene pan
    float incr_y = y / factor;                      //Determines the incr value on y-axis for scene pan

    GLfloat m[16];                                  //Temporary array to store a matrix 4x4
    glGetFloatv(GL_MODELVIEW_MATRIX, m);            //Gets the current model view matrix into the temporary array m

    //Recovering the x-axis (s) and the y-axis (w) vectors of the camera's coordinate system
    Vector3D s (m[0], m[4], m[8]);
    Vector3D w (m[1], m[5], m[9]);

    Point& vrp = camera->vrp;

    //Updating the View Reference Point (due to user pan action) according to the camera's coordinate system
    SetVRP (vrp.x + incr_x*s.x + incr_y*w.x,        //x
            vrp.y + incr_x*s.y + incr_y*w.y,        //y
            vrp.z + incr_x*s.z + incr_y*w.z);       //z
}

/// <summary>
/// Method called to do zooming
/// </summary>
/// <param name="x"> The quantity of zoom required </param>
void CIView::View::DoZooming (int quantity) {
    float f = camera->zoom + 0.015f * camera->zoom * quantity;    //Computes the new zoom factor, according to the current zoom factor and the quantity received
    SetZoomFactor (f);                                            //Updates the zoom factor
}
/***************************************************************************************************************
************************************ endregion Protected Utility Methods ***************************************
****************************************************************************************************************/





///<************************************************************************************************************>
///<************************************ region Public Utility Methods *****************************************>
///<************************************************************************************************************>

/// <summary>
/// Method called to get the current camera orientation
/// </summary>
/// <returns> A reference to the current camera orientation </returns>
Orientation& CIView::View::GetCameraOrientation() {
    return camera->orientation;
}

/// <summary>
/// Method called to get the current camera type
/// </summary>
/// <returns> An integer that identifies the current camera type </returns>
int CIView::View::GetCameraType() {
    return camera->type;
}

/// <summary>
/// Method called to get the current camera zoom value
/// </summary>
/// <returns> The current camera zoom value </returns>
float CIView::View::GetCameraZoom() {
    return camera->zoom;
}

/// <summary>
/// Method called to get the current view reference point
/// </summary>
/// <returns> The current view reference point </returns>
Point& CIView::View::GetCameraVrp() {
    return camera->vrp;
}

/// <summary>
/// Method called to get a reference to the 3D scene
/// </summary>
/// <returns> A reference to the 3D scene </returns>
CIView::Scene& CIView::View::GetScene() {
    return scene;
}

/// <summary>
/// Method called to get the current feedback mode
/// </summary>
/// <returns> The current feedback mode </returns>
unsigned int CIView::View::GetFeedbackMode () {
    return feedbackMode;
}

/// <summary>
/// Method called to set the current feedback mode
/// </summary>
/// <param name="f"> The feedback mode desidered </param>
void CIView::View::SetFeedbackMode (unsigned int f) {
    feedbackMode = f;
}

/// <summary>
/// Method called to get the a reference to the selection feedback object
/// </summary>
/// <returns> A reference to the selection feedback object </returns>
CIView::FeedbackSelection& CIView::View::GetFeedbackSelection() {
    return feedbackSelection;
}

/// <summary>
/// Method called to set the current interactive action
/// </summary>
/// <param name="action"> The interactive action required </param>
void CIView::View::SetInteractiveAction (int action) {
    CurrentInteractiveAction = action;

    //Setting the feedback mode
    switch (action) {
        case PRIMITIVES_TRANSLATION:            //TRANSLATION
            feedbackMode = FEEDBACK_TRANSLATION;
            break;

        case PRIMITIVES_SCALING:                //SCALING
            feedbackMode = FEEDBACK_SCALING;
            break;

        case PRIMITIVES_ROTATION:               //ROTATION
            feedbackMode = FEEDBACK_ROTATION;
            break;

        default:
            feedbackMode = FEEDBACK_NONE;
            break;
    }
    updateGL();
}

/// <summary>
/// Method called to set the current operation to do
/// </summary>
/// <param name="opID"> An integer that identifies the operation to do </param>
void CIView::View::SetCurrentOperationID (int opID) {
    currentOpID = opID;
}

/// <summary>
/// Method called to select geometries
/// </summary>
/// <param name="x"> The x-axis coordinate of the selection rectangle centre </param>
/// <param name="y"> The y-axis coordinate of the selection rectangle centre </param>
/// <param name="width"> The width of the selection rectangle </param>
/// <param name="height"> The height of the selection rectangle </param>
/// <returns> A boolean to indicate if has been selected at least one primitive </returns>
bool CIView::View::SelectGeometriesInVolume (double x, double y, double width, double height) {
    vector<const char*> geometriesNames;
    map<const char*, Geometry*>::iterator it = scene.geometries.begin();
    unsigned int numberOfNames = 0;

    //Saving the names of the geometries in the scene and computing the total number of names
    while (it != scene.geometries.end()) {
        geometriesNames.push_back (it->second->GetName().c_str());
        numberOfNames += it->second->GetNumberOfNames();
        it++;
    }

    makeCurrent();                                          //Makes this widget the current widget for OpenGL operations

    int vp[4];                                              //A temporary array to store the current viewport info
    glGetIntegerv (GL_VIEWPORT, vp);                        //Gets the current viewport

    SetModelView();                                         //Sets up the model view matrix
    glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

    glPushMatrix();
        glLoadIdentity();                                       //Loads the Identity matrix

        gluPickMatrix (x, vp[3]-y, width, height, vp);          //Defines a picking region

        SetViewFrustum();                                       //Sets the view frustum

        unsigned int bufferSize = numberOfNames*5;
        GLuint* buffer = new GLuint[bufferSize];                //Defines a buffer used to store information about the hit primitives
        glSelectBuffer (bufferSize, buffer);                    //Sets up the selection buffer

        glRenderMode (GL_SELECT);                               //Sets the render mode for selection


        glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);             //Sets the polygon mode to GL_FILL (needed for a correct selection)

        glInitNames();                                          //Initializes the OpenGL names stack

        glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
        scene.LoadGeometriesNames();                            //Loads the names that identify the geometries in the stack
        glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

        int hits = glRenderMode (GL_RENDER);                    //Changes the render mode and retrieves the number of hit primitives
    glPopMatrix();

    map<Geometry*, bool> selected;

    //Processing the selection result
    if (hits > 0) {                                 //If at least one primitive has been hit
        int geometryIndex = 0;                      //the index (into the scene geometries) of the geometry that include the primitive hit
        Geometry* geometry = 0;
        const char* geometryName = 0;

        for (int i = 1; i <= hits; i++) {                   //for each primitive hit
            geometryIndex = buffer[i*5-2];                  //retrieves the index (into the scene geometries) associated with the geometry ("parent" of the primitive hit)
            geometryName = geometriesNames[geometryIndex];  //retrieves the name associated with the geometry ("parent" of the primitive hit)
            geometry = scene.GetGeometry (geometryName);    //retrieves the geometry "parent" of the primitive hit

            if (!geometry->hasPrimitivesSelected)
                geometry->hasPrimitivesSelected = true;     //sets the boolean to indicate that the geometry has some primitive selected

            //If the geometry it's not already selected, we must select all its vertices and primitives
            if (!(selected[geometry])) {
                VertexLib& vertices = geometry->GetVertices();
                VertexIter v = vertices.begin();

                while (v != vertices.end()) {
                    (*v)->selected = true;
                    v++;
                }

                FaceLib& faces = geometry->GetFaces();
                FaceIter f = faces.begin();

                while (f != faces.end()) {
                    (*f)->selected = true;
                    f++;
                }
                selected[geometry] = true;
            }
        }
    }
    SetPrimitivesSelected (hits > 0);                       //Signals if some primitive has been selected

    delete [] buffer;                                       //Deletes the selection buffer

    glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
    glPolygonMode (GL_FRONT_AND_BACK, polygonMode);         //Restores the polygon mode

    return (hits > 0);
}

/// <summary>
/// Method called to select geometries faces
/// </summary>
/// <param name="x"> The x-axis coordinate of the selection rectangle centre </param>
/// <param name="y"> The y-axis coordinate of the selection rectangle centre </param>
/// <param name="width"> The width of the selection rectangle </param>
/// <param name="height"> The height of the selection rectangle </param>
/// <returns> A boolean to indicate if has been selected at least one primitive </returns>
bool CIView::View::SelectFacesInVolume (double x, double y, double width, double height) {
    vector<const char*> geometriesNames;
    map<const char*, Geometry*>::iterator it = scene.geometries.begin();
    unsigned int numberOfFaces = 0;

    //Saving the names of the geometries in the scene and computing the total number of faces
    while (it != scene.geometries.end()) {
        geometriesNames.push_back (it->second->GetName().c_str());
        numberOfFaces += it->second->GetFaces().size();
        it++;
    }

    makeCurrent();                                          //Makes this widget the current widget for OpenGL operations

    int vp[4];                                              //A temporary array to store the current viewport info
    glGetIntegerv (GL_VIEWPORT, vp);                        //Gets the current viewport

    SetModelView();                                         //Sets up the model view matrix
    glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

    glPushMatrix();
        glLoadIdentity();                                       //Loads the Identity matrix

        gluPickMatrix (x, vp[3]-y, width, height, vp);          //Defines a picking region

        SetViewFrustum();                                       //Sets the view frustum

        unsigned int bufferSize = numberOfFaces*5;
        GLuint* buffer = new GLuint[bufferSize];                //Defines a buffer used to store information about the hit faces
        glSelectBuffer (bufferSize, buffer);                    //Sets up the selection buffer

        glRenderMode (GL_SELECT);                               //Sets the render mode for selection

        glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);             //Sets the polygon mode to GL_FILL (needed for a correct selection)

        glInitNames();                                          //Initializes the OpenGL names stack

        glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
        scene.LoadFacesNames();                                 //Loads the faces names in the stack
        glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

        int hits = glRenderMode (GL_RENDER);                    //Changes the render mode and retrieves the number of hit faces
    glPopMatrix();


    //Processing the selection result
    if (hits > 0) {                                 //If at least one face has been hit
        int geometryIndex = 0;                      //the index (into the scene geometries) of the geometry that include the face hit
        int faceIndex = 0;                          //the index (into the geometry faces) of the faces hit
        Geometry* geometry = 0;
        const char* geometryName = 0;
        Face* face;


        for (int i = 1; i <= hits; i++) {                   //for each face hit
            geometryIndex = buffer[i*5-2];                  //retrieves the index (into the scene geometries) associated with the geometry ("parent" of the face hit)
            faceIndex = buffer[i*5-1];                      //retrieves the index (into the geometry faces) associated with the face hit

            geometryName = geometriesNames[geometryIndex];  //retrieves the name associated with the geometry ("parent" of the face hit)
            geometry = scene.GetGeometry (geometryName);    //retrieves the geometry "parent" of the face hit

            if (!geometry->hasPrimitivesSelected)
                geometry->hasPrimitivesSelected = true;     //sets the boolean to indicate that the geometry has some primitive selected

            face = geometry->GetFaces()[faceIndex];         //retreives the face hit
            face->SetSelected();                            //sets the face as selected
        }
    }
    SetPrimitivesSelected (hits > 0);                       //Signals if some primitive has been selected

    delete [] buffer;                                       //Deletes the selection buffer

    glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
    glPolygonMode (GL_FRONT_AND_BACK, polygonMode);         //Restores the polygon mode

    return (hits > 0);
}

/// <summary>
/// Method called to select geometries vertices
/// </summary>
/// <param name="x"> The x-axis coordinate of the selection rectangle centre </param>
/// <param name="y"> The y-axis coordinate of the selection rectangle centre </param>
/// <param name="width"> The width of the selection rectangle </param>
/// <param name="height"> The height of the selection rectangle </param>
/// <returns> A boolean to indicate if has been selected at least one primitive </returns>
bool CIView::View::SelectVerticesInVolume (double x, double y, double width, double height) {
    vector<const char*> geometriesNames;
    map<const char*, Geometry*>::iterator it = scene.geometries.begin();
    unsigned int numberOfVertices = 0;

    //Saving the names of the geometries in the scene and computing the total number of vertices
    while (it != scene.geometries.end()) {
        geometriesNames.push_back (it->second->GetName().c_str());
        numberOfVertices += it->second->GetVertices().size();
        it++;
    }

    makeCurrent();                                          //Makes this widget the current widget for OpenGL operations

    int vp[4];                                              //A temporary array to store the current viewport info
    glGetIntegerv (GL_VIEWPORT, vp);                        //Gets the current viewport

    SetModelView();                                         //Sets up the model view matrix
    glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

    glPushMatrix();
        glLoadIdentity();                                       //Loads the Identity matrix

        gluPickMatrix (x, vp[3]-y, width, height, vp);          //Defines a picking region

        SetViewFrustum();                                       //Sets the view frustum

        unsigned int bufferSize = numberOfVertices*5;
        GLuint* buffer = new GLuint[bufferSize];                //Defines a buffer used to store information about the hit vertices
        glSelectBuffer (bufferSize, buffer);                    //Sets up the selection buffer

        glRenderMode (GL_SELECT);                               //Sets the render mode for selection


        glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);             //Sets the polygon mode to GL_FILL (needed for a correct selection)

        glInitNames();                                          //Initializes the OpenGL names stack

        glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
        scene.LoadVerticesNames();                              //Loads the vertices names in the stack
        glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

        int hits = glRenderMode (GL_RENDER);                    //Changes the render mode and retrieves the number of hit vertices
    glPopMatrix();


    //Processing the selection result
    if (hits > 0) {                                 //If at least one vertex has been hit
        int geometryIndex = 0;                      //the index (into the scene geometries) of the geometry that include the vertex hit
        int vertexIndex = 0;                        //the index (into the geometry vertices) of the vertices hit
        Geometry* geometry = 0;
        const char* geometryName = 0;
        Vertex* vertex;


        for (int i = 1; i <= hits; i++) {                   //for each vertex hit
            geometryIndex = buffer[i*5-2];                  //retrieves the index (into the scene geometries) associated with the geometry ("parent" of the vertex hit)
            vertexIndex = buffer[i*5-1];                    //retrieves the index (into the geometry vertices) associated with the vertex hit

            geometryName = geometriesNames[geometryIndex];  //retrieves the name associated with the geometry ("parent" of the vertex hit)
            geometry = scene.GetGeometry (geometryName);    //retrieves the geometry "parent" of the vertex hit

            if (!geometry->hasPrimitivesSelected)
                geometry->hasPrimitivesSelected = true;     //sets the boolean to indicate that the geometry has some primitive selected

            vertex = geometry->GetVertices()[vertexIndex];  //retreives the vertex hit
            vertex->selected = true;                        //sets the vertex as selected
        }
    }
    SetPrimitivesSelected (hits > 0);                       //Signals if some primitive has been selected

    delete [] buffer;                                       //Deletes the selection buffer

    glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
    glPolygonMode (GL_FRONT_AND_BACK, polygonMode);         //Restores the polygon mode

    return (hits > 0);
}

/// <summary>
/// Method called to select a single vertex
/// </summary>
/// <param name="x"> The x-axis coordinate of the mouse click </param>
/// <param name="y"> The y-axis coordinate of the mouse click </param>
/// <returns>
/// A pair that contains a pointer to the geometry which
/// the selected vertex belong to and the index of the
/// vertex within the geometry vertices library
/// </returns>
std::pair<Geometry*,int> CIView::View::SelectVertex (double x, double y) {
    vector<const char*> geometriesNames;
    map<const char*, Geometry*>::iterator it = scene.geometries.begin();
    unsigned int numberOfVertices = 0;
    double width = 7;
    double height = 7;

    //Saving the names of the geometries in the scene and computing the total number of vertices
    while (it != scene.geometries.end()) {
        geometriesNames.push_back (it->second->GetName().c_str());
        numberOfVertices += it->second->GetVertices().size();
        it++;
    }

    makeCurrent();                                          //Makes this widget the current widget for OpenGL operations

    int vp[4];                                              //A temporary array to store the current viewport info
    glGetIntegerv (GL_VIEWPORT, vp);                        //Gets the current viewport

    SetModelView();                                         //Sets up the model view matrix
    glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

    glPushMatrix();
        glLoadIdentity();                                       //Loads the Identity matrix

        gluPickMatrix (x, vp[3]-y, width, height, vp);          //Defines a picking region

        SetViewFrustum();                                       //Sets the view frustum

        unsigned int bufferSize = numberOfVertices*5;
        GLuint* buffer = new GLuint[bufferSize];                //Defines a buffer used to store information about the hit vertices
        glSelectBuffer (bufferSize, buffer);                    //Sets up the selection buffer

        glRenderMode (GL_SELECT);                               //Sets the render mode for selection


        glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);             //Sets the polygon mode to GL_FILL (needed for a correct selection)

        glInitNames();                                          //Initializes the OpenGL names stack

        glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
        scene.LoadVerticesNames();                              //Loads the vertices names in the stack
        glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

        int hits = glRenderMode (GL_RENDER);                    //Changes the render mode and retrieves the number of hit vertices
    glPopMatrix();

    int geometryIndex = 0;                      //The index (into the scene geometries) of the geometry that include the vertex hit
    int vertexIndex = 0;                        //The index (into the geometry vertices) of the vertices hit
    Geometry* geometry = 0;
    const char* geometryName = 0;
    Vertex* vertex = 0;
    pair<Geometry*,int> pair;
    double minZ = 9999999999999;

    //Processing the selection result
    if (hits > 0) {                                     //If at least one vertex has been hit
        for (int i = 1; i <= hits; i++) {                       //for each vertex hit
            if (buffer[i*5-4] < minZ) {
                minZ = buffer[i*5-4];
                geometryIndex = buffer[i*5-2];                  //retrieves the index (into the scene geometries) associated with the geometry ("parent" of the vertex hit)
                vertexIndex = buffer[i*5-1];                    //retrieves the index (into the geometry vertices) associated with the vertex hit
            }
        }
        geometryName = geometriesNames[geometryIndex];  //retrieves the name associated with the geometry ("parent" of the vertex hit)
        geometry = scene.GetGeometry (geometryName);    //retrieves the geometry "parent" of the vertex hit

        if (!geometry->hasPrimitivesSelected)
            geometry->hasPrimitivesSelected = true;     //sets the boolean to indicate that the geometry has some primitive selected

        vertex = geometry->GetVertices()[vertexIndex];  //retreives the vertex hit
        vertex->selected = true;                        //sets the vertex as selected
    }
    SetPrimitivesSelected (hits > 0);                       //Signals if some primitive has been selected

    pair.first = geometry;
    pair.second = vertexIndex;

    delete [] buffer;                                       //Deletes the selection buffer

    glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
    glPolygonMode (GL_FRONT_AND_BACK, polygonMode);         //Restores the polygon mode

    return pair;
}

/// <summary>
/// Method called to select the translation feedback axes
/// </summary>
/// <param name="x"> The x-axis coordinate of the selection rectangle centre </param>
/// <param name="y"> The y-axis coordinate of the selection rectangle centre </param>
/// <returns> The id of the selected axis </returns>
unsigned int CIView::View::SelectFeedbackTranslationAxes (double x, double y) {
    makeCurrent();                                          //Makes this widget the current widget for OpenGL operations

    int vp[4];                                              //A temporary array to store the current viewport info
    glGetIntegerv (GL_VIEWPORT, vp);                        //Gets the current viewport

    SetModelView();                                         //Sets up the model view matrix
    glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

    glPushMatrix();
        glLoadIdentity();                                       //Loads the Identity matrix

        gluPickMatrix (x, vp[3]-y, 1.0, 1.0, vp);               //Defines a picking region

        SetViewFrustum();                                       //Sets the view frustum

        GLuint buffer[16];                                      //Defines a buffer used to store information about the hit axis
        glSelectBuffer (16, buffer);                            //Sets up the selection buffer

        glRenderMode (GL_SELECT);                               //Sets the render mode for selection

        glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);             //Sets the polygon mode to GL_FILL (needed for a correct selection)

        glInitNames();                                          //Initializes the OpenGL names stack
        glPushName (0);                                         //Pushes a fictitious name in the OpenGL names stack


        glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
        Feedback_Translation.LoadAxesNames (*camera);            //Loads the axes names in the stack
        glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

        int hits = glRenderMode (GL_RENDER);                    //Changes the render mode and retrieves the number of hit axis
    glPopMatrix();


    glMatrixMode (GL_MODELVIEW);                                //Selects the Model View Matrix
    glPolygonMode (GL_FRONT_AND_BACK, polygonMode);             //Restores the polygon mode

    //Processing the selection result
    if (hits > 0) {                                 //If at least one axis has been hit
        for (unsigned int i = 1; i <= hits; i++) {
            switch (buffer[i*4-1]) {
                case FeedbackTranslation::X_AXIS:
                    Feedback_Translation.SelectX();              //Selects the x-axis
                    return FeedbackTranslation::X_AXIS;

                case FeedbackTranslation::Y_AXIS:
                    Feedback_Translation.SelectY();              //Selects the y-axis
                    return FeedbackTranslation::Y_AXIS;

                case FeedbackTranslation::Z_AXIS:
                    Feedback_Translation.SelectZ();              //Selects the z-axis
                    return FeedbackTranslation::Z_AXIS;

                case FeedbackTranslation::ALL_AXES:
                    Feedback_Translation.SelectAll();            //Selects all axes
                    return FeedbackTranslation::ALL_AXES;
            }
        }
    }
    Feedback_Translation.SelectAll();
    return FeedbackTranslation::ALL_AXES;

}

/// <summary>
/// Method called to select the scaling feedback axes
/// </summary>
/// <param name="x"> The x-axis coordinate of the selection rectangle centre </param>
/// <param name="y"> The y-axis coordinate of the selection rectangle centre </param>
/// <returns> The id of the selected axis </returns>
unsigned int CIView::View::SelectFeedbackScalingAxes (double x, double y) {
    makeCurrent();                                          //Makes this widget the current widget for OpenGL operations

    int vp[4];                                              //A temporary array to store the current viewport info
    glGetIntegerv (GL_VIEWPORT, vp);                        //Gets the current viewport

    SetModelView();                                         //Sets up the model view matrix
    glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

    glPushMatrix();
        glLoadIdentity();                                       //Loads the Identity matrix

        gluPickMatrix (x, vp[3]-y, 1.0, 1.0, vp);               //Defines a picking region

        SetViewFrustum();                                       //Sets the view frustum

        GLuint buffer[16];                                      //Defines a buffer used to store information about the hit axis
        glSelectBuffer (16, buffer);                            //Sets up the selection buffer

        glRenderMode (GL_SELECT);                               //Sets the render mode for selection

        glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);             //Sets the polygon mode to GL_FILL (needed for a correct selection)

        glInitNames();                                          //Initializes the OpenGL names stack
        glPushName (0);                                         //Pushes a fictitious name in the OpenGL names stack


        glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
        Feedback_Scaling.LoadAxesNames (*camera);                //Loads the axes names in the stack
        glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

        int hits = glRenderMode (GL_RENDER);                    //Changes the render mode and retrieves the number of hit axis
    glPopMatrix();


    glMatrixMode (GL_MODELVIEW);                                //Selects the Model View Matrix
    glPolygonMode (GL_FRONT_AND_BACK, polygonMode);             //Restores the polygon mode

    //Processing the selection result
    if (hits > 0) {                                 //If at least one axis has been hit
        for (unsigned int i = 1; i <= hits; i++) {
            switch (buffer[i*4-1]) {
                case FeedbackScaling::X_AXIS:
                    Feedback_Scaling.SelectX();              //Selects the x-axis
                    return FeedbackScaling::X_AXIS;

                case FeedbackScaling::Y_AXIS:
                    Feedback_Scaling.SelectY();              //Selects the y-axis
                    return FeedbackScaling::Y_AXIS;

                case FeedbackScaling::Z_AXIS:
                    Feedback_Scaling.SelectZ();              //Selects the z-axis
                    return FeedbackScaling::Z_AXIS;

                case FeedbackScaling::ALL_AXES:
                    Feedback_Scaling.SelectAll();            //Selects all axes
                    return FeedbackScaling::ALL_AXES;
            }
        }
    }
    Feedback_Scaling.SelectAll();
    return FeedbackScaling::ALL_AXES;

}

/// <summary>
/// Method called to select the rotation feedback axes
/// </summary>
/// <param name="x"> The x-axis coordinate of the selection rectangle centre </param>
/// <param name="y"> The y-axis coordinate of the selection rectangle centre </param>
/// <returns> The id of the selected axis </returns>
unsigned int CIView::View::SelectFeedbackRotationAxes (double x, double y) {
    makeCurrent();                                          //Makes this widget the current widget for OpenGL operations

    int vp[4];                                              //A temporary array to store the current viewport info
    glGetIntegerv (GL_VIEWPORT, vp);                        //Gets the current viewport

    SetModelView();                                         //Sets up the model view matrix
    glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

    glPushMatrix();
        glLoadIdentity();                                       //Loads the Identity matrix

        gluPickMatrix (x, vp[3]-y, 1.0, 1.0, vp);               //Defines a picking region

        SetViewFrustum();                                       //Sets the view frustum

        GLuint buffer[16];                                      //Defines a buffer used to store information about the hit axis
        glSelectBuffer (16, buffer);                            //Sets up the selection buffer

        glRenderMode (GL_SELECT);                               //Sets the render mode for selection

        glPolygonMode (GL_FRONT_AND_BACK, GL_FILL);             //Sets the polygon mode to GL_FILL (needed for a correct selection)

        glInitNames();                                          //Initializes the OpenGL names stack
        glPushName (0);                                         //Pushes a fictitious name in the OpenGL names stack

        glMatrixMode (GL_MODELVIEW);                            //Selects the Model View Matrix
        Feedback_Rotation.LoadAxesNames (*camera);               //Loads the axes names in the stack
        glMatrixMode (GL_PROJECTION);                           //Selects the Projection Matrix

        int hits = glRenderMode (GL_RENDER);                    //Changes the render mode and retrieves the number of hit axis
    glPopMatrix();


    glMatrixMode (GL_MODELVIEW);                                //Selects the Model View Matrix
    glPolygonMode (GL_FRONT_AND_BACK, polygonMode);             //Restores the polygon mode

    //Processing the selection result
    if (hits > 0) {                                 //If at least one axis has been hit
        for (unsigned int i = 1; i <= hits; i++) {
            switch (buffer[i*4-1]) {
                case FeedbackRotation::X_AXIS:
                    Feedback_Rotation.SelectX();              //Selects the x-axis
                    return FeedbackRotation::X_AXIS;

                case FeedbackRotation::Y_AXIS:
                    Feedback_Rotation.SelectY();              //Selects the y-axis
                    return FeedbackRotation::Y_AXIS;

                case FeedbackRotation::Z_AXIS:
                    Feedback_Rotation.SelectZ();              //Selects the z-axis
                    return FeedbackRotation::Z_AXIS;

                //case FeedbackRotation::ALL_AXES:
                //    switch (camera->type) {
                //        case Camera::TOP:
                //            Feedback_Rotation.SelectY();              //Selects the y-axis
                //            return FeedbackRotation::Y_AXIS;
                //
                //        case Camera::FRONT:
                //            Feedback_Rotation.SelectZ();              //Selects the z-axis
                //            return FeedbackRotation::Z_AXIS;
                //
                //        case Camera::RIGHT:
                //            Feedback_Rotation.SelectX();              //Selects the x-axis
                //            return FeedbackRotation::X_AXIS;
                //    }
                //    Feedback_Rotation.SelectAll();            //Selects all axes
                //    return FeedbackRotation::ALL_AXES;
            }
        }
    }
    switch (camera->type) {
        case Camera::TOP:
            Feedback_Rotation.SelectY();              //Selects the y-axis
            return FeedbackRotation::Y_AXIS;

        case Camera::FRONT:
            Feedback_Rotation.SelectZ();              //Selects the z-axis
            return FeedbackRotation::Z_AXIS;

        case Camera::RIGHT:
            Feedback_Rotation.SelectX();              //Selects the x-axis
            return FeedbackRotation::X_AXIS;
    }
    Feedback_Rotation.SelectAll();
    return FeedbackRotation::ALL_AXES;

}

/// <summary>
/// Method called to transform the coordinates based on window coordinates
/// system to the corresponding in the world coordinates system
/// </summary>
/// <param name="x"> The window x-axis coordinate </param>
/// <param name="y"> The window y-axis coordinate </param>
void CIView::View::WindowToWorldCoordinates(float *x, float *y) {
    Point viewportCentre ((float)width()/2.0f, (float)height()/2.0f);
    //float fov = camera->fov / camera->zoom;
    //float fovInRadians = fov / 360 * PI;
    //float scenePlaneHeight = tan (fovInRadians) * camera->vrpDistance;
    //float scenePlaneWidth = scenePlaneHeight * camera->aspectRatio;
    float scenePlaneHeight = (abs(camera->bottom) + abs(camera->top)) / 2.0f / camera->zoom;
    float scenePlaneWidth = (abs (camera->left) + abs (camera->right)) / 2.0f / camera->zoom;

    (*x) -= viewportCentre.x;           //Translates x-axis coordinate according to the viewport centre
    (*y) -= viewportCentre.y;           //Translates y-axis coordinate according to the viewport centre

    (*x) /= viewportCentre.x;           //Normalizes the x-axis coordinate (into 0.0 - 1.0)
    (*y) /= viewportCentre.y;           //Normalizes the y-axis coordinate (into 0.0 - 1.0)

    (*x) = (*x) * scenePlaneWidth;      //Computes the x-axis coordinate in the scene clipping plane
    (*y) = (*y) * scenePlaneHeight;     //Computes the y-axis coordinate in the scene clipping plane

    Point& vrp = camera->vrp;           //Gets a reference to the view reference point of the current camera

    //Translate the mouse click coordinates according to the current view reference point coordinates
    switch (camera->type) {
        case Camera::TOP:
            (*x) += vrp.x;
            (*y) += vrp.z;
            break;

        case Camera::FRONT:
            (*x) += vrp.x;
            (*y) -= vrp.y;
            break;

        case Camera::RIGHT:
            (*x) -= vrp.z;
            (*y) -= vrp.y;
            break;

        case Camera::USER:
            //TODO
            //la z corrisponde (pi� o meno) alla y quando camera->orientation.x > 20 e < 150
            //la z corrisponde (pi� o meno) alla x quando camera->orientation.y > 20 e < 150
            //si pu� fare una specia di interpolazione
            float c = 0;//;cos (float (camera->orientation.x));
            float s = 0;//-sin (float (camera->orientation.y));
            (*x) += vrp.x - s * vrp.z;
            (*y) -= vrp.y + c * vrp.z;
            //(*x) += vrp.x;
            //(*y) -= vrp.y;
            break;
    }
}

/// <summary>
/// Method called to transform the coordinates based on window coordinates
/// system to the corresponding in the normalized coordinates system
/// </summary>
/// <param name="x"> The window x-axis coordinate </param>
/// <param name="y"> The window y-axis coordinate </param>
void CIView::View::WindowToNormalizedCoordinates (float *x, float *y) {
    Point viewportCentre ((float)width()/2.0f, (float)height()/2.0f);
    //float fov = camera->fov / camera->zoom;
    //float fovInRadians = fov / 360 * PI;
    //float zNearPlaneHeight = tan (fovInRadians) * camera->zNear;
    //float zNearPlaneWidth = zNearPlaneHeight * camera->aspectRatio;
    float zNearPlaneHeight = (abs(camera->bottom) + abs(camera->top)) / 2.0f / camera->zoom;
    float zNearPlaneWidth = (abs(camera->left) + abs(camera->right)) / 2.0f / camera->zoom;

    (*y) = height() - *y;               //Translates y-axis coordinate according to the viewport (0,0) position

    (*x) -= viewportCentre.x;           //Translates x-axis coordinate according to the viewport centre
    (*y) -= viewportCentre.y;           //Translates y-axis coordinate according to the viewport centre

    (*x) /= viewportCentre.x;           //Normalizes the x-axis coordinate (into 0.0 - 1.0)
    (*y) /= viewportCentre.y;           //Normalizes the y-axis coordinate (into 0.0 - 1.0)

    (*x) = (*x) * zNearPlaneWidth;      //Computes the x-axis coordinate in the zNear clipping plane
    (*y) = (*y) * zNearPlaneHeight;     //Computes the y-axis coordinate in the zNear clipping plane
}
/***************************************************************************************************************
*************************************** endregion Public Utility Methods ***************************************
****************************************************************************************************************/










///<************************************************************************************************************>
///<********************************* region Keyboard Events Handlers Methods **********************************>
///<************************************************************************************************************>

/// <summary>
/// Key Pressed event handler
/// </summary>
/// <param name="e"> Key Pressed event </param>
void CIView::View::keyPressEvent (QKeyEvent *e) {
    using namespace CIGui;

    ViewsContainer* parent = (ViewsContainer*)parentWidget();

    switch (e->key()) {
        case Qt::Key_L:            //'L'
            ToggleLighting();                   //Toggles lighting
            break;

        case Qt::Key_C:            //'C'
            ResetCurrentCamera();               //Resets the current camera
            break;

        case Qt::Key_F:            //'F'
            parent->ToggleViewFullScreenMode (this);                //Toggles the full screen mode for the view
            break;
    }

    if (CurrentInteractiveAction != NONE) {
        e->ignore();                           //Ignores the event
        return;
    }

    switch (e->key()) {
        case Qt::Key_Plus:          //'+'
            DoZooming (10);                     //Zoom In
            break;

        case Qt::Key_Minus:         //'-'
            DoZooming (-10);                    //Zoom Out
            break;

        case Qt::Key_Up:            //'up_arrow'
            if (e->modifiers()&Qt::ShiftModifier)                   //If shift modifier is pressed
                DoPanning (0, -10);                                 //does panning
            else if (camera->type == Camera::USER)                  //else if the current camera is of type USER
                SetCameraOrientation (camera->orientation.x-5,      //modifies the camera orientation
                                      camera->orientation.y,
                                      camera->orientation.z);
            break;

        case Qt::Key_Down:          //'down_arrow'
            if (e->modifiers()&Qt::ShiftModifier)                   //If shift modifier is pressed
                DoPanning (0, 10);                                  //does panning
            else if (camera->type == Camera::USER)                  //else if the current camera is of type USER
                SetCameraOrientation (camera->orientation.x+5,      //modifies the camera orientation
                                      camera->orientation.y,
                                      camera->orientation.z);
            break;

        case Qt::Key_Left:          //'left_arrow'
            if (e->modifiers()&Qt::ShiftModifier)                   //If shift modifier is pressed
                DoPanning (10, 0);                                  //does panning
            else if (camera->type == Camera::USER)                  //else if the current camera is of type USER
                if (e->modifiers()&Qt::ControlModifier)
                    SetCameraOrientation (camera->orientation.x,        //modifies the camera orientation for z-rotation
                                          camera->orientation.y,
                                          camera->orientation.z-5);
                else
                    SetCameraOrientation (camera->orientation.x,        //modifies the camera orientation
                                          camera->orientation.y-5,
                                          camera->orientation.z);
            break;

        case Qt::Key_Right:         //'right_arrow'
            if (e->modifiers()&Qt::ShiftModifier)                   //If shift modifier is pressed
                DoPanning (-10, 0);                                 //does panning
            else if (camera->type == Camera::USER)                  //else if the current camera is of type USER
                if (e->modifiers()&Qt::ControlModifier)
                    SetCameraOrientation (camera->orientation.x,        //modifies the camera orientation for z-rotation
                                          camera->orientation.y,
                                          camera->orientation.z+5);
                else
                    SetCameraOrientation (camera->orientation.x,        //modifies the camera orientation
                                          camera->orientation.y+5,
                                          camera->orientation.z);
            break;

        default:
            e->ignore();                    //Ignores the event
            break;
    }
}

/// <summary>
/// Key Released event handler
/// </summary>
/// <param name="e"> Key Released event </param>
void CIView::View::keyReleaseEvent (QKeyEvent *e) {
}
/***************************************************************************************************************
*********************************** endregion Keyboard Events Handlers Methods *********************************
****************************************************************************************************************/














///<************************************************************************************************************>
///<********************************** region Mouse Events Handlers Methods ************************************>
///<************************************************************************************************************>

/// <summary>
/// Mouse Pressed event handler
/// </summary>
/// <param name="e"> Mouse Pressed event </param>
void CIView::View::mousePressEvent (QMouseEvent *e) {
    using namespace CIGui;

    //Saving the click position
    click.x = e->x();
    click.y = e->y();

    switch (CurrentInteractiveAction) {
        case NONE:              //NONE
            //Determining the type of interaction required
            if (camera->type == Camera::USER && e->button()&Qt::RightButton && !(e->modifiers()&(Qt::ShiftModifier | Qt::ControlModifier | Qt::AltModifier))) {
                CurrentInteractiveAction = ROTATION;
                setCursor (ROTATION_CURSOR);  //Sets the cursor for roration action
            }
            else if (e->button()&Qt::LeftButton && e->modifiers()&Qt::ShiftModifier) {
                CurrentInteractiveAction = ZOOM;
                setCursor (ZOOMING_CURSOR);   //Sets the cursor for zooming action
            }
            else if (e->button()&Qt::LeftButton) {
                CurrentInteractiveAction = PAN;
                setCursor (PANNING_CURSOR);   //Sets the cursor for panning action
            }
            else if (camera->type == Camera::USER && e->button()&Qt::MidButton) {
                CurrentInteractiveAction = Z_ROTATION;
                setCursor (Z_ROTATION_CURSOR);   //Sets the cursor for z-rotation action
            }
            break;

        case MESH_CREATION:             //MESH CREATION
        case SELECTION:                 //SELECTION
        case PRIMITIVES_TRANSLATION:    //TRANSLATION
        case PRIMITIVES_SCALING:        //SCALING
        case PRIMITIVES_ROTATION:       //ROTATION
        case PRIMITIVES_EXTRUSION:      //EXTRUSION
            if (e->button() == Qt::LeftButton) {
                operationManager.CreateOperation (currentOpID);                 //Creates the current operation to do

                if (operationManager.todoOp)
                    operationManager.todoOp->MousePressEvent (this, e);
            }
            break;
    }

    e->accept();                    //Accepts the event
}

/// <summary>
/// Mouse Released event handler
/// </summary>
/// <param name="e"> Mouse Released event </param>
void CIView::View::mouseReleaseEvent (QMouseEvent *e) {
    using namespace CIGui;

    int x_angle = camera->orientation.x + drag.y;       //The current angle of rotation based on the x axis
    int y_angle = camera->orientation.y + drag.x;       //The current angle of rotation based on the y axis
    int z_angle = camera->orientation.z + incrZ;        //The current angle of rotation based on the z axis

    switch (CurrentInteractiveAction) {
        case ROTATION:          //ROTATION
            while (x_angle < 0)                         //Keeps the angle (based on the x axis) positive
                x_angle += 360;

            while (y_angle < 0)                         //Keeps the angle (based on the y axis) positive
                y_angle += 360;

            SetCameraOrientation (x_angle % 360,        //Updates the camera orientation
                                  y_angle % 360,        //according to the mouse drag value
                                  camera->orientation.z);
            drag.x = 0;
            drag.y = 0;
            CurrentInteractiveAction = NONE;    //Sets current interactive action as the null interactive action
            setCursor (DEFAULT_CURSOR);     //Sets the default cursor
            break;

        case Z_ROTATION:        //Z_ROTATION
            while (z_angle < 0)                             //Keeps the angle (based on the z axis) positive
                z_angle += 360;

            SetCameraOrientation (camera->orientation.x,    //Updates the camera orientation
                                  camera->orientation.y,
                                  z_angle % 360);
            incrZ = 0;
            CurrentInteractiveAction = NONE;    //Sets current interactive action as the null interactive action
            setCursor (DEFAULT_CURSOR);     //Sets the default cursor
            break;

        case PAN:               //PAN
        case ZOOM:              //ZOOM
            CurrentInteractiveAction = NONE;    //Sets current interactive action as the null interactive action
            setCursor (DEFAULT_CURSOR);     //Sets the default cursor
            break;

        case MESH_CREATION:             //MESH CREATION
        case SELECTION:                 //SELECTION
        case PRIMITIVES_TRANSLATION:    //TRANSLATION
        case PRIMITIVES_SCALING:        //SCALING
        case PRIMITIVES_ROTATION:       //ROTATION
        case PRIMITIVES_EXTRUSION:      //EXTRUSION
            if (operationManager.todoOp) {
                operationManager.todoOp->MouseReleaseEvent (this, e);

                if (operationManager.CheckOperationStatus())
                    emit OperationCompleted (true);
            }
            break;
    }

    e->accept();                        //Accepts the event
}

/// <summary>
/// Mouse Moved event handler
/// </summary>
/// <param name="e"> Mouse Moved event </param>
void CIView::View::mouseMoveEvent (QMouseEvent *e) {
    makeCurrent();          //Makes this widget the current widget for OpenGL operations (needed to accept all mouse events)

    int x_angle;
    int y_angle;
    int z_angle;

    //According to the current interactive action
    switch (CurrentInteractiveAction) {
        case ROTATION:         //ROTATION
            drag.x = e->x() - click.x;          //Determines the drag value on x-axis for scene rotation based on y-axis
            drag.y = e->y() - click.y;          //Determines the drag value on y-axis for scene rotation based on x-axis

            x_angle = camera->orientation.x + drag.y;       //The current angle of rotation based on the x axis
            y_angle = camera->orientation.y + drag.x;       //The current angle of rotation based on the y axis

            while (x_angle < 0)                             //Keeps the angle (based on the x axis) positive
                x_angle += 360;

            while (y_angle < 0)                             //Keeps the angle (based on the y axis) positive
                y_angle += 360;

            emit CameraOrientationChanged (x_angle % 360,
                                           y_angle % 360,
                                           camera->orientation.z);

            updateGL();                         //Updates the view
            break;

        case Z_ROTATION:       //Z_ROTATION
            incrZ = e->x() - click.x;           //Determines the drag value on x-axis for scene rotation based on z-axis

            z_angle = camera->orientation.z + incrZ;        //The current angle of rotation based on the z axis

            while (z_angle < 0)                             //Keeps the angle (based on the z axis) positive
                z_angle += 360;


            emit CameraOrientationChanged (camera->orientation.x,
                                           camera->orientation.y,
                                           z_angle % 360);

            updateGL();                         //Updates the view
            break;

        case ZOOM:              //ZOOM
            DoZooming (click.y - e->y());       //Does zoom according to the mouse movement
            click.y = e->y();                   //Updates the cursor y coordinate
            break;

        case PAN:               //PAN
            DoPanning (click.x - e->x(), e->y() - click.y);     //Does panning according to the mouse movement
            click.x = e->x();                                   //Updates the x cursor coordinate
            click.y = e->y();                                   //Updates the y cursor coordinate
            break;

        case MESH_CREATION:             //MESH CREATION
        case SELECTION:                 //SELECTION
        case PRIMITIVES_TRANSLATION:    //TRANSLATION
        case PRIMITIVES_SCALING:        //SCALING
        case PRIMITIVES_ROTATION:       //ROTATION
        case PRIMITIVES_EXTRUSION:      //EXTRUSION
            if (operationManager.todoOp)
                operationManager.todoOp->MouseMoveEvent (this, e);
            break;
    }

    e->accept();                    //Accepts the event
}

/// <summary>
/// Wheel event handler
/// </summary>
/// <param name="e"> Wheel event </param>
void CIView::View::wheelEvent (QWheelEvent *e) {
    makeCurrent();                  //Makes this widget the current widget for OpenGL operations (needed to accept all wheel events)

     //According to the current interactive action
    if (CurrentInteractiveAction != NONE
        && operationManager.todoOp)
            operationManager.todoOp->WheelEvent (this, e);
    else
        DoZooming (0.1*e->delta());     //Does zoom according to the quantity of wheel rotation (delta)

    e->accept();                    //Accepts the event
}

/// <summary>
/// Focus in event handler
/// </summary>
/// <param name="e"> Focus in event </param>
void CIView::View::focusInEvent (QFocusEvent* e) {
    makeCurrent();          //Makes this widget the current widget for OpenGL operations (needed to accept all mouse events)

    glClearColor (ON_FOCUS_BACKGROUND_COLOR.r,
                  ON_FOCUS_BACKGROUND_COLOR.g,
                  ON_FOCUS_BACKGROUND_COLOR.b,
                  ON_FOCUS_BACKGROUND_COLOR.a);             //Sets the clear values for the color buffer
    updateGL();
}

/// <summary>
/// Focus out event handler
/// </summary>
/// <param name="e"> Focus out event </param>
void CIView::View::focusOutEvent (QFocusEvent* e) {
    makeCurrent();          //Makes this widget the current widget for OpenGL operations (needed to accept all mouse events)

    glClearColor (DEFAULT_BACKGROUND_COLOR.r,
                  DEFAULT_BACKGROUND_COLOR.g,
                  DEFAULT_BACKGROUND_COLOR.b,
                  DEFAULT_BACKGROUND_COLOR.a);              //Sets the clear values for the color buffer
    updateGL();
}

/// <summary>
/// Mouse Enter event handler
/// </summary>
/// <param name="e"> Mouse Enter event </param>
void CIView::View::enterEvent (QEvent * e) {
    makeCurrent();          //Makes this widget the current widget for OpenGL operations (needed to accept all mouse events)

    glClearColor (ON_FOCUS_BACKGROUND_COLOR.r,
                  ON_FOCUS_BACKGROUND_COLOR.g,
                  ON_FOCUS_BACKGROUND_COLOR.b,
                  ON_FOCUS_BACKGROUND_COLOR.a);             //Sets the clear values for the color buffer
    updateGL();
}

/// <summary>
/// Mouse Leave event handler
/// </summary>
/// <param name="e"> Mouse Leave event </param>
void CIView::View::leaveEvent (QEvent * e) {
    makeCurrent();          //Makes this widget the current widget for OpenGL operations (needed to accept all mouse events)

    glClearColor (DEFAULT_BACKGROUND_COLOR.r,
                  DEFAULT_BACKGROUND_COLOR.g,
                  DEFAULT_BACKGROUND_COLOR.b,
                  DEFAULT_BACKGROUND_COLOR.a);              //Sets the clear values for the color buffer
    updateGL();
}
/***************************************************************************************************************
************************************ endregion Mouse Events Handlers Methods ***********************************
****************************************************************************************************************/
